///////////////////////////////////////////////////////////////////////////////
//
// This example demonstrates how to use a GrabberListener derived
// callback handler object to process events
//
// A class CListener is derived from GrabberListener. It is used to handle callbacks.
// The method CListener::frameReady() simulates a time expensive processing. Therefore,
// the method CListener::frameReady() is not called for every captured buffer. 
// The member CListener::m_pBufferWritten is used to record, which buffers were processed
// by CListener::frameReady().
// After snapImages() returns, the main function will save the buffers that were not
// processed. This sample shows that all buffers have been copied correctly to the
// MembufferCollection, although CListener::frameReady() was not called for every buffer.
//
#include <windows.h>
#include <process.h>
#include <shlobj.h>
#include <iostream>
#include <sstream>
#include <string>
#include "PlexDOController.h"
#include "ICCallBack.h"

extern DOStatus doStatus;

void audioPulseThread(void* p)
{
	int pulseUnitLength_ms =  *(int*)p ;
	generateRandomFreqPulse(pulseUnitLength_ms, CameraAudioPulseChannel, CameraAudioEventChannel);
}

void KBListenerThread(void* p)
{
	KBListener();
}

static int CALLBACK BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
{

	if (uMsg == BFFM_INITIALIZED)
	{
		std::string tmp = (const char *)lpData;
		std::cout << "path: " << tmp << std::endl;
		SendMessage(hwnd, BFFM_SETSELECTION, TRUE, lpData);
	}

	return 0;
}

std::string BrowseFolder(std::string saved_path)
{
	TCHAR path[MAX_PATH];

	//const char * path_param = saved_path.c_str();
	std::wstring wsaved_path(saved_path.begin(), saved_path.end());
	const wchar_t * path_param = wsaved_path.c_str();

	BROWSEINFO bi = { 0 };
	bi.lpszTitle = ("Browse for folder...");
	bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE;
	bi.lpfn = BrowseCallbackProc;
	bi.lParam = (LPARAM)path_param;

	LPITEMIDLIST pidl = SHBrowseForFolder(&bi);

	if (pidl != 0)
	{
		//get the name of the folder and put it in path
		SHGetPathFromIDList(pidl, path);

		//free memory used
		IMalloc * imalloc = 0;
		if (SUCCEEDED(SHGetMalloc(&imalloc)))
		{
			imalloc->Free(pidl);
			imalloc->Release();
		}

		return path;
	}

	return "";
}

int main(int argc, char* argv[])
{
	// thread handlers
	HANDLE h_opto;
	HANDLE h_do;
	HANDLE h_apulse;

	//minimum audio synchronization pluse half period length
	int pulseUnitLength_ms = 10;

	std::string path;
	std::string saveFileName;

	//screan print
	std::cout << "                                        " << std::endl;
	std::cout << "****************************************" << std::endl;
	std::cout << "Plexon digital output controlling client" << std::endl;
	std::cout << "****************************************" << std::endl;
	std::cout << "  Author: Sile Hu, yuehusile@gmail.com  " << std::endl;
	std::cout << "                Wang Lab                " << std::endl;
	std::cout << "      Department of Anesthesiology      " << std::endl;
	std::cout << " New York University School of Medicine " << std::endl;
	std::cout << "****************************************" << std::endl;
	std::cout << "                                        " << std::endl;

	//start hotkey listening thread
	HANDLE h_kbl = (HANDLE)_beginthread(KBListenerThread, 0, NULL);
	
	// Plexon digital output initialization
	initPlexDO();

	std::cout << "Please choose following options to enable described functions" << std::endl;
	std::cout << "input relevant number and press [enter] to continue:" << std::endl;
	std::cout << "****************************************" << std::endl;
	std::cout << "                                        " << std::endl;
	std::cout << "1 -- opto & laser, with IC camera recording " << std::endl;
	std::cout << "2 -- opto & laser, with IC camera & Sony recording " << std::endl;
	std::cout << "3 -- opto & laser, with Sony camera recording " << std::endl;
	std::cout << "4 -- opto & laser, no camera recording " << std::endl;
	std::cout << "5 -- laser only" << std::endl;
	std::cout << "6 -- opto only" << std::endl;
	std::cout << std::endl;

	char option = std::cin.get();
	bool goodOptionFlag = false;
	char key;
	while (!goodOptionFlag)
	{
		switch (option)
		{
		case '1': 
			std::cout << "your choice:  1 -- opto & laser, with IC camera recording" << std::endl;
			goodOptionFlag = true;
			h_do = (HANDLE)_beginthread(PlexLaserThread, 0, NULL);
			//h_apulse = (HANDLE)_beginthread(audioPulseThread, 0, &pulseUnitLength_ms);
			h_opto = (HANDLE)_beginthread(PlexOptoThread, 0, NULL);
			std::cout << "Please choose a folder for IC video:" << std::endl;
			path = BrowseFolder(".");
			std::cout << "path: " << path << std::endl;
			if (path == "")
				exit(0);
			std::cout << "Please input file name:" << std::endl;

			std::cin >> saveFileName;
			saveFileName = path + "\\" + saveFileName + ".avi";
			std::cout << "*******************************************************************************" << std::endl;
			std::cout << "Warning: Please make sure [Arm Recording] is active" << std::endl;
			std::cout << "         and recording-trigger event channel is set to event(" << (int)doStatus.recTrigChn << ") in PlexControl" << std::endl;
			std::cout << "         or start Plexon recording manually" << std::endl;
			std::cout << "         BEFORE press [Enter] to start" << std::endl;
			std::cout << "         the video synchronization may fail otherwise" << std::endl;
			std::cout << "*******************************************************************************" << std::endl;
			std::cout << "Press [enter] to start recording!" << std::endl;
			std::cin.get();
			std::cin.get();
			PlexSendRecordingStart();
			std::cout << "Plexon recording started" << std::endl;
			runGrabber(saveFileName);
			break;
		case '2':
			std::cout << "your choice:  2 -- opto & laser, with IC camera & Sony recording" << std::endl;
			goodOptionFlag = true;
			h_opto = (HANDLE)_beginthread(PlexOptoThread, 0, NULL);
			h_do = (HANDLE)_beginthread(PlexLaserThread, 0, NULL);
			std::cout << "Please choose a folder for IC video:" << std::endl;
			path = BrowseFolder(".");
			std::cout << "path: " << path << std::endl;
			if (path == "")
				exit(0);
			std::cout << "Please input file name:" << std::endl;

			std::cin >> saveFileName;
			saveFileName = path + "\\" + saveFileName + ".avi";
			std::cin.get();
			std::cout << "*******************************************************************************" << std::endl;
			std::cout << "Warning: Please make sure [Arm Recording] is active" << std::endl;
			std::cout << "         and recording-trigger event channel is set to event(" << (int)doStatus.recTrigChn << ") in PlexControl" << std::endl;
			std::cout << "         or start Plexon recording manually" << std::endl;
			std::cout << "         BEFORE press [Enter] to start" << std::endl;
			std::cout << "         the video synchronization may fail otherwise" << std::endl;
			std::cout << "*******************************************************************************" << std::endl;
			std::cout << "Warning: Please start Sony camera recording BEFORE press [Enter] to start" << std::endl;
			std::cout << "         the video synchronization may fail otherwise" << std::endl;
			std::cout << "*******************************************************************************" << std::endl;
			std::cout << "Press [enter] to start recording!" << std::endl;
			std::cin.get();
			
			PlexSendRecordingStart();
			std::cout << "Plexon recording started" << std::endl;

			h_apulse = (HANDLE)_beginthread(audioPulseThread, 0, &pulseUnitLength_ms);
			runGrabber(saveFileName);
			break;
		case '3':
			std::cout << "your choice:  3 -- opto & laser, with Sony camera recording" << std::endl;
			goodOptionFlag = true;
			h_opto = (HANDLE)_beginthread(PlexOptoThread, 0, NULL);
			h_do = (HANDLE)_beginthread(PlexLaserThread, 0, NULL);

			std::cin.get();
			std::cout << "*******************************************************************************" << std::endl;
			std::cout << "Warning: Please make sure [Arm Recording] is active" << std::endl;
			std::cout << "         and recording-trigger event channel is set to event(" << (int)doStatus.recTrigChn << ") in PlexControl" << std::endl;
			std::cout << "         or start Plexon recording manually" << std::endl;
			std::cout << "         BEFORE press [Enter] to start" << std::endl;
			std::cout << "         the video synchronization may fail otherwise" << std::endl;
			std::cout << "*******************************************************************************" << std::endl;
			std::cout << "Warning: Please start Sony camera recording first BEFORE press [Enter] to start" << std::endl;
			std::cout << "         the video synchronization may fail otherwise" << std::endl;
			std::cout << "*******************************************************************************" << std::endl;
			std::cout << "Press [enter] to start recording!" << std::endl;
			std::cin.get();

			PlexSendRecordingStart();
			std::cout << "Plexon recording started" << std::endl;

			h_apulse = (HANDLE)_beginthread(audioPulseThread, 0, &pulseUnitLength_ms);

			std::cout << "Press [enter] to exit!" << std::endl;
			while (1)
			{
				key = std::cin.get();
				Sleep(1000);
				if (key == '\n')
					break;
			}
			break;
		case '4':
			std::cout << "your choice:  4 -- opto & laser, no camera recording" << std::endl;
			goodOptionFlag = true;
			h_opto = (HANDLE)_beginthread(PlexOptoThread, 0, NULL);
			h_do = (HANDLE)_beginthread(PlexLaserThread, 0, NULL);
			std::cin.get();
			std::cout << "*******************************************************************************" << std::endl;
			std::cout << "Warning: Please make sure [Arm Recording] is active" << std::endl;
			std::cout << "         and recording-trigger event channel is set to event(" << (int)doStatus.recTrigChn << ") in PlexControl" << std::endl;
			std::cout << "         or start Plexon recording manually" << std::endl;
			std::cout << "         BEFORE press [Enter] to start" << std::endl;
			std::cout << "*******************************************************************************" << std::endl;
			std::cout << "Press [enter] to start recording!" << std::endl;
			key = std::cin.get();

			PlexSendRecordingStart();
			std::cout << "Plexon recording started" << std::endl;
			std::cout << "Press [enter] to exit!" << std::endl;
			while (1)
			{
				key = std::cin.get();
				Sleep(1000);
				if (key == '\n')
					break;
			}

			break;
		case '5':
			std::cout << "your choice:  5 -- laser only" << std::endl;
			goodOptionFlag = true;
			h_do = (HANDLE)_beginthread(PlexLaserThread, 0, NULL);

			std::cin.get();
			std::cout << "*******************************************************************************" << std::endl;
			std::cout << "Warning: Please make sure [Arm Recording] is active" << std::endl;
			std::cout << "         and recording-trigger event channel is set to event(" << (int)doStatus.recTrigChn << ") in PlexControl" << std::endl;
			std::cout << "         or start Plexon recording manually" << std::endl;
			std::cout << "         BEFORE press [Enter] to start" << std::endl;
			std::cout << "*******************************************************************************" << std::endl;
			std::cout << "Press [enter] to start recording!" << std::endl;
			key = std::cin.get();

			PlexSendRecordingStart();
			std::cout << "Plexon recording started" << std::endl;
			std::cout << "Press [enter] to exit!" << std::endl;
			while (1)
			{
				key = std::cin.get();
				Sleep(1000);
				if (key == '\n')
					break;
			}
			break;
		case '6':
			std::cout << "your choice:  6 -- opto only" << std::endl;
			goodOptionFlag = true;
			h_opto = (HANDLE)_beginthread(PlexOptoThread, 0, NULL);

			std::cin.get();
			std::cout << "*******************************************************************************" << std::endl;
			std::cout << "Warning: Please make sure [Arm recording] is active" << std::endl;
			std::cout << "         and recording-trigger event channel is set to event(" << (int)doStatus.recTrigChn << ") in PlexControl" << std::endl;
			std::cout << "         or start Plexon recording manually" << std::endl;
			std::cout << "         BEFORE press [Enter] to start" << std::endl;
			std::cout << "*******************************************************************************" << std::endl;
			std::cout << "Press [enter] to start recording!" << std::endl;

			PlexSendRecordingStart();
			std::cout << "Plexon recording started" << std::endl;
			std::cout << "Press [enter] to exit!" << std::endl;
			while (1)
			{
				key = std::cin.get();
				Sleep(1000);
				if (key == '\n')
					break;
			}
			break;
		default: std::cout << "Please input one of the numbers from 1-6" << std::endl;
	    }
}

	//std::cout << "Please choose a folder:" << std::endl;
	//std::string path = BrowseFolder(".");
	//std::cout <<"path: "<< path << std::endl;
	//std::cout << "Please input file name:" << std::endl;

	//std::string saveFileName;
	//std::cin >> saveFileName;
	//saveFileName = path + "\\" + saveFileName + ".avi";

	//initPlexDO();

	//HANDLE h_apulse = (HANDLE)_beginthread(audioPulseThread, 0, &pulseUnitLength_ms);

	//HANDLE h_kbl = (HANDLE)_beginthread(KBListenerThread, 0, NULL);

	//HANDLE h_do = (HANDLE)_beginthread(PlexLaserThread, 0, NULL);

	//HANDLE h_opto = (HANDLE)_beginthread(PlexOptoThread, 0, NULL);

	//std::cout << "Press [enter] to start capturing!";
	//std::cin.get();

	//runGrabber(saveFileName);
	if (option == 2 || option == 3)
	CloseHandle(h_apulse);
	CloseHandle(h_kbl);
	if (option == 1 || option == 2 || option == 3 || option == 4 || option == 5)
	CloseHandle(h_do);
	if (option == 1 || option == 2 || option == 3 || option == 4 || option == 6)
	CloseHandle(h_opto);

	return 0;
}

